<!DOCTYPE html>
<html lang="en-us">
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    
<meta charset="UTF-8">
<title>Solving Concurrency Issues | Elasticsearch: The Definitive Guide [2.x] | Elastic</title>
<link rel="home" href="index.html" title="Elasticsearch: The Definitive Guide [2.x]">
<link rel="up" href="relations.html" title="Handling Relationships">
<link rel="prev" href="denormalization-concurrency.html" title="Denormalization and Concurrency">
<link rel="next" href="nested-objects.html" title="Nested Objects">
<meta name="DC.type" content="Learn/Docs/Legacy/Elasticsearch/Definitive Guide/2.x">
<meta name="DC.subject" content="Elasticsearch">
<meta name="DC.identifier" content="2.x">
<meta name="robots" content="noindex,nofollow">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.optimizely.com/js/18132920325.js"></script>
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
    <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
    <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
    <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
    <link rel="manifest" href="/manifest.json">
    <meta name="apple-mobile-web-app-title" content="Elastic">
    <meta name="application-name" content="Elastic">
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content="/mstile-144x144.png">
    <meta name="theme-color" content="#ffffff">
    <meta name="naver-site-verification" content="936882c1853b701b3cef3721758d80535413dbfd">
    <meta name="yandex-verification" content="d8a47e95d0972434">
    <meta name="localized" content="true">
    <meta name="st:robots" content="follow,index">
    <meta property="og:image" content="https://www.elastic.co/static/images/elastic-logo-200.png">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon-precomposed" sizes="64x64" href="/favicon_64x64_16bit.png">
    <link rel="apple-touch-icon-precomposed" sizes="32x32" href="/favicon_32x32.png">
    <link rel="apple-touch-icon-precomposed" sizes="16x16" href="/favicon_16x16.png">
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" type="text/css" href="/guide/static/styles.css">
  </head>

  <!--© 2015-2021 Elasticsearch B.V. Copying, publishing and/or distributing without written permission is strictly prohibited.-->

  <body>
    <!-- Google Tag Manager -->
    <script>dataLayer = [];</script><noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-58RLH5" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-58RLH5');</script>
    <!-- End Google Tag Manager -->

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-12395217-16"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'UA-12395217-16');
    </script>

    <!--BEGIN QUALTRICS WEBSITE FEEDBACK SNIPPET-->
    <script type="text/javascript">
      (function(){var g=function(e,h,f,g){
      this.get=function(a){for(var a=a+"=",c=document.cookie.split(";"),b=0,e=c.length;b<e;b++){for(var d=c[b];" "==d.charAt(0);)d=d.substring(1,d.length);if(0==d.indexOf(a))return d.substring(a.length,d.length)}return null};
      this.set=function(a,c){var b="",b=new Date;b.setTime(b.getTime()+6048E5);b="; expires="+b.toGMTString();document.cookie=a+"="+c+b+"; path=/; "};
      this.check=function(){var a=this.get(f);if(a)a=a.split(":");else if(100!=e)"v"==h&&(e=Math.random()>=e/100?0:100),a=[h,e,0],this.set(f,a.join(":"));else return!0;var c=a[1];if(100==c)return!0;switch(a[0]){case "v":return!1;case "r":return c=a[2]%Math.floor(100/c),a[2]++,this.set(f,a.join(":")),!c}return!0};
      this.go=function(){if(this.check()){var a=document.createElement("script");a.type="text/javascript";a.src=g;document.body&&document.body.appendChild(a)}};
      this.start=function(){var a=this;window.addEventListener?window.addEventListener("load",function(){a.go()},!1):window.attachEvent&&window.attachEvent("onload",function(){a.go()})}};
      try{(new g(100,"r","QSI_S_ZN_emkP0oSe9Qrn7kF","https://znemkp0ose9qrn7kf-elastic.siteintercept.qualtrics.com/WRSiteInterceptEngine/?Q_ZID=ZN_emkP0oSe9Qrn7kF")).start()}catch(i){}})();
    </script><div id="ZN_emkP0oSe9Qrn7kF"><!--DO NOT REMOVE-CONTENTS PLACED HERE--></div>
    <!--END WEBSITE FEEDBACK SNIPPET-->

    <div id="elastic-nav" style="display:none;"></div>
    <script src="https://www.elastic.co/elastic-nav.js"></script>

    <!-- Subnav -->
    <div>
      <div>
        <div class="tertiary-nav d-none d-md-block">
          <div class="container">
            <div class="p-t-b-15 d-flex justify-content-between nav-container">
              <div class="breadcrum-wrapper"><span><a href="/guide/" style="font-size: 14px; font-weight: 600; color: #000;">Docs</a></span></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="main-container">
      <section id="content">
        <div class="content-wrapper">

          <section id="guide" lang="en">
            <div class="container">
              <div class="row">
                <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                  <!-- start body -->
                  <div class="page_header">
<p>
  <strong>WARNING</strong>: The 2.x versions of Elasticsearch have passed their
  <a href="https://www.elastic.co/support/eol">EOL dates</a>. If you are running
  a 2.x version, we strongly advise you to upgrade.
</p>
<p>
  This documentation is no longer maintained and may be removed. For the latest
  information, see the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html">current
  Elasticsearch documentation</a>.
</p>
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: The Definitive Guide [2.x]</a></span>
»
<span class="breadcrumb-link"><a href="modeling-your-data.html">Modeling Your Data</a></span>
»
<span class="breadcrumb-link"><a href="relations.html">Handling Relationships</a></span>
»
<span class="breadcrumb-node">Solving Concurrency Issues</span>
</div>
<div class="navheader">
<span class="prev">
<a href="denormalization-concurrency.html">« Denormalization and Concurrency</a>
</span>
<span class="next">
<a href="nested-objects.html">Nested Objects »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="concurrency-solutions"></a>Solving Concurrency Issues<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch-definitive-guide/edit/2.x/400_Relationships/26_Concurrency_solutions.asciidoc">edit</a>
</h2>
</div></div></div>
<p>The problem comes when we want to allow more than one person to rename files
or directories <em>at the same time</em>.  Imagine that you rename the <code class="literal">/clinton</code>
directory, which contains hundreds of thousands of files.  Meanwhile, another
user renames the single file <code class="literal">/clinton/projects/elasticsearch/README.txt</code>.
That user’s change, although it started after yours, will probably finish more
quickly.</p>
<p>One of two things will happen:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
You have decided to use <code class="literal">version</code> numbers, in which case your mass rename
will fail with a version conflict when it hits the renamed
<code class="literal">README.txt</code> file.
</li>
<li class="listitem">
You didn’t use versioning, and your changes will overwrite the changes from
the other user.
</li>
</ul>
</div>
<p>The problem is that Elasticsearch does not support
<a href="http://en.wikipedia.org/wiki/ACID_transactions" class="ulink" target="_top">ACID transactions</a>.  Changes to
individual documents are ACIDic, but not changes involving multiple documents.</p>
<p>If your main data store is a relational database, and Elasticsearch is simply
being used as a search engine or as a way to improve performance, make
your changes in the database first and replicate those changes to
Elasticsearch after they have succeeded. This way, you benefit from the ACID
transactions available in the database, and all changes to Elasticsearch happen
in the right order. Concurrency is dealt with in the relational database.</p>
<p>If you are not using a relational store, these concurrency issues need to
be dealt with at the Elasticsearch level.  The following are three practical
solutions using Elasticsearch, all of which involve some form of locking:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
Global Locking
</li>
<li class="listitem">
Document Locking
</li>
<li class="listitem">
Tree Locking
</li>
</ul>
</div>
<div class="tip admon">
<div class="icon"></div>
<div class="admon_content">
<p>The solutions described in this section could also be implemented by applying the same
principles while using an external system instead of Elasticsearch.</p>
</div>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="global-lock"></a>Global Locking<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch-definitive-guide/edit/2.x/400_Relationships/26_Concurrency_solutions.asciidoc">edit</a>
</h3>
</div></div></div>
<p>We can avoid concurrency issues completely by allowing only one process to
make changes at any time.  Most changes will involve only a few files and will
complete very quickly.  A rename of a top-level directory may block all other
changes for longer, but these are likely to be much less frequent.</p>
<p>Because document-level changes in Elasticsearch are ACIDic, we can use the
existence or absence of a document as a global lock.  To request a
lock, we try to <code class="literal">create</code> the global-lock document:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/lock/global/_create
{}</pre>
</div>
<p>If this <code class="literal">create</code> request fails with a conflict exception,
another process has already been granted the global lock and we will have to
try again later.  If it succeeds, we are now the proud owners of the
global lock and we can continue with our changes.  Once we are finished, we
must release the lock by deleting the global lock document:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">DELETE /fs/lock/global</pre>
</div>
<p>Depending on how frequent changes are, and how long they take, a global lock
could restrict the performance of a system significantly.  We can increase
parallelism by making our locking more fine-grained.</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="document-locking"></a>Document Locking<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch-definitive-guide/edit/2.x/400_Relationships/26_Concurrency_solutions.asciidoc">edit</a>
</h3>
</div></div></div>
<p>Instead of locking the whole filesystem, we could lock individual documents
by using the same technique as previously described.
We can use a <a class="xref" href="scroll.html" title="Scroll">scrolled search</a> to retrieve all documents that would be affected by the change and
create a lock file for each one:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/lock/_bulk
{ "create": { "_id": 1}} <a id="CO261-1"></a><i class="conum" data-value="1"></i>
{ "process_id": 123    } <a id="CO261-2"></a><i class="conum" data-value="2"></i>
{ "create": { "_id": 2}}
{ "process_id": 123    }</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO261-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The ID of the <code class="literal">lock</code> document would be the same as the ID of  the file
that should be locked.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO261-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">process_id</code> is a unique ID that represents the process that
wants to perform the changes.</p>
</td>
</tr>
</table>
</div>
<p>If some files are already locked, parts of the <code class="literal">bulk</code> request will fail and we
will have to try again.</p>
<p>Of course, if we try to lock <em>all</em> of the files again, the <code class="literal">create</code> statements
that we used previously will fail for any file that is already locked by us!
Instead of a simple <code class="literal">create</code> statement, we need an <code class="literal">update</code> request with an
<code class="literal">upsert</code> parameter and this <code class="literal">script</code>:</p>
<div class="pre_wrapper lang-groovy">
<pre class="programlisting prettyprint lang-groovy">if ( ctx._source.process_id != process_id ) { <a id="CO262-1"></a><i class="conum" data-value="1"></i>
  assert false;  <a id="CO262-2"></a><i class="conum" data-value="2"></i>
}
ctx.op = 'noop'; <a id="CO262-3"></a><i class="conum" data-value="3"></i></pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO262-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">process_id</code> is a parameter that we pass into the script.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO262-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p><code class="literal">assert false</code> will throw an exception, causing the update to fail.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO262-3"><i class="conum" data-value="3"></i></a></p>
</td>
<td align="left" valign="top">
<p>Changing the <code class="literal">op</code> from <code class="literal">update</code> to <code class="literal">noop</code> prevents the update request
from making any changes, but still returns success.</p>
</td>
</tr>
</table>
</div>
<p>The full <code class="literal">update</code> request looks like this:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">POST /fs/lock/1/_update
{
  "upsert": { "process_id": 123 },
  "script": "if ( ctx._source.process_id != process_id )
  { assert false }; ctx.op = 'noop';"
  "params": {
    "process_id": 123
  }
}</pre>
</div>
<p>If the document doesn’t already exist, the <code class="literal">upsert</code> document is inserted—​much
the same as the previous <code class="literal">create</code> request.  However, if the
document <em>does</em> exist, the script looks at the <code class="literal">process_id</code> stored in the
document.  If the <code class="literal">process_id</code> matches, no update is performed (<code class="literal">noop</code>) but the
script returns successfully.  If it is different, <code class="literal">assert false</code> throws an exception
and you know that the lock has failed.</p>
<p>Once all locks have been successfully created, you can proceed with your changes.</p>
<p>Afterward, you must release all of the locks, which you can do by
retrieving all of the locked documents and performing a bulk delete:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">POST /fs/_refresh <a id="CO263-1"></a><i class="conum" data-value="1"></i>

GET /fs/lock/_search?scroll=1m <a id="CO263-2"></a><i class="conum" data-value="2"></i>
{
    "sort" : ["_doc"],
    "query": {
        "match" : {
            "process_id" : 123
        }
    }
}

PUT /fs/lock/_bulk
{ "delete": { "_id": 1}}
{ "delete": { "_id": 2}}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO263-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">refresh</code> call ensures that all <code class="literal">lock</code> documents are visible to
the search request.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO263-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>You can use a <a class="xref" href="scroll.html" title="Scroll"><code class="literal">scroll</code></a> query when you need to retrieve large
numbers of results with a single search request.</p>
</td>
</tr>
</table>
</div>
<p>Document-level locking enables fine-grained access control, but creating lock
files for millions of documents can be expensive.  In some cases,
you can achieve fine-grained locking with much less work, as shown in the
following directory tree scenario.</p>
</div>

<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="tree-locking"></a>Tree Locking<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch-definitive-guide/edit/2.x/400_Relationships/26_Concurrency_solutions.asciidoc">edit</a>
</h3>
</div></div></div>
<p>Rather than locking every involved document as in the previous example, we
could lock just part of the directory tree.  We will need exclusive access
to the file or directory that we want to rename, which can be achieved with an
<em>exclusive lock</em> document:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">{ "lock_type": "exclusive" }</pre>
</div>
<p>And we need shared locks on any parent directories, with a <em>shared lock</em>
document:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">{
  "lock_type":  "shared",
  "lock_count": 1 <a id="CO264-1"></a><i class="conum" data-value="1"></i>
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO264-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">lock_count</code> records the number of processes that hold a shared lock.</p>
</td>
</tr>
</table>
</div>
<p>A process that wants to rename <code class="literal">/clinton/projects/elasticsearch/README.txt</code>
needs an <em>exclusive</em> lock on that file, and a <em>shared</em> lock on <code class="literal">/clinton</code>,
<code class="literal">/clinton/projects</code>, and <code class="literal">/clinton/projects/elasticsearch</code>.</p>
<p>A simple <code class="literal">create</code> request will suffice for the exclusive lock, but the shared
lock needs a scripted update to implement some extra logic:</p>
<div class="pre_wrapper lang-groovy">
<pre class="programlisting prettyprint lang-groovy">if (ctx._source.lock_type == 'exclusive') {
  assert false; <a id="CO265-1"></a><i class="conum" data-value="1"></i>
}
ctx._source.lock_count++ <a id="CO265-2"></a><i class="conum" data-value="2"></i></pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO265-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>If the <code class="literal">lock_type</code> is <code class="literal">exclusive</code>, the <code class="literal">assert</code> statement will throw
an exception, causing the update request to fail.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO265-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>Otherwise, we increment the <code class="literal">lock_count</code>.</p>
</td>
</tr>
</table>
</div>
<p>This script handles the case where the <code class="literal">lock</code> document already exists, but we
will also need an <code class="literal">upsert</code> document to handle the case where it doesn’t exist
yet. The full update request is as follows:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">POST /fs/lock/%2Fclinton/_update <a id="CO266-1"></a><i class="conum" data-value="1"></i>
{
  "upsert": { <a id="CO266-2"></a><i class="conum" data-value="2"></i>
    "lock_type":  "shared",
    "lock_count": 1
  },
  "script": "if (ctx._source.lock_type == 'exclusive')
  { assert false }; ctx._source.lock_count++"
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO266-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The ID of the document is <code class="literal">/clinton</code>, which is URL-encoded to <code class="literal">%2fclinton</code>.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO266-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">upsert</code> document will be inserted if the document does not already
exist.</p>
</td>
</tr>
</table>
</div>
<p>Once we succeed in gaining a shared lock on all of the parent directories, we
try to <code class="literal">create</code> an exclusive lock on the file itself:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/lock/%2Fclinton%2fprojects%2felasticsearch%2fREADME.txt/_create
{ "lock_type": "exclusive" }</pre>
</div>
<p>Now, if somebody else wants to rename the <code class="literal">/clinton</code> directory, they would
have to gain an exclusive lock on that path:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/lock/%2Fclinton/_create
{ "lock_type": "exclusive" }</pre>
</div>
<p>This request would fail because a <code class="literal">lock</code> document with the same ID already
exists. The other user would have to wait until our operation is done and we
have released our locks. The exclusive lock can just be deleted:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">DELETE /fs/lock/%2Fclinton%2fprojects%2felasticsearch%2fREADME.txt</pre>
</div>
<p>The shared locks need another script that decrements the <code class="literal">lock_count</code> and, if
the count drops to zero, deletes the <code class="literal">lock</code> document:</p>
<div class="pre_wrapper lang-groovy">
<pre class="programlisting prettyprint lang-groovy">if (--ctx._source.lock_count == 0) {
  ctx.op = 'delete' <a id="CO267-1"></a><i class="conum" data-value="1"></i>
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO267-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>Once the <code class="literal">lock_count</code> reaches <code class="literal">0</code>, the <code class="literal">ctx.op</code> is changed from <code class="literal">update</code>
to <code class="literal">delete</code>.</p>
</td>
</tr>
</table>
</div>
<p>This update request would need to be run for each parent directory in reverse
order, from longest to shortest:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">POST /fs/lock/%2Fclinton%2fprojects%2felasticsearch/_update
{
  "script": "if (--ctx._source.lock_count == 0) { ctx.op = 'delete' } "
}</pre>
</div>
<p>Tree locking gives us fine-grained concurrency control with the minimum of
effort. Of course, it is not applicable to every situation—​the data model
must have some sort of access path like the directory tree for it to work.</p>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<p>None of the three options—​global, document, or tree locking—​deals with
the thorniest problem associated with locking: what happens if the process
holding the lock dies?</p>
<p>The unexpected death of a process leaves us with two problems:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
How do we know that we can release the locks held by the dead process?
</li>
<li class="listitem">
How do we clean up the change that the dead process did not manage to complete?
</li>
</ul>
</div>
<p>These topics are beyond the scope of this book, but you will need to give them
some thought  if you decide to use locking.</p>
</div>
</div>
<p>While denormalization is a good choice for many projects, the need for locking
schemes can make for complicated implementations. Instead, Elasticsearch
provides two models that help us deal with related entities:
<em>nested objects</em> and <em>parent-child relationships</em>.</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="denormalization-concurrency.html">« Denormalization and Concurrency</a>
</span>
<span class="next">
<a href="nested-objects.html">Nested Objects »</a>
</span>
</div>
</div>

                  <!-- end body -->
                </div>
                <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                  <div id="rtpcontainer" style="display: block;">
                    <div class="mktg-promo">
                      <h3>Most Popular</h3>
                      <ul class="icons">
                        <li class="icon-elasticsearch-white"><a href="https://www.elastic.co/webinars/getting-started-elasticsearch?baymax=default&amp;elektra=docs&amp;storm=top-video">Get Started with Elasticsearch: Video</a></li>
                        <li class="icon-kibana-white"><a href="https://www.elastic.co/webinars/getting-started-kibana?baymax=default&amp;elektra=docs&amp;storm=top-video">Intro to Kibana: Video</a></li>
                        <li class="icon-logstash-white"><a href="https://www.elastic.co/webinars/introduction-elk-stack?baymax=default&amp;elektra=docs&amp;storm=top-video">ELK for Logs &amp; Metrics: Video</a></li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </section>

        </div>


<div id="elastic-footer"></div>
<script src="https://www.elastic.co/elastic-footer.js"></script>
<!-- Footer Section end-->

      </section>
    </div>

<script src="/guide/static/jquery.js"></script>
<script type="text/javascript" src="/guide/static/docs.js"></script>
<script type="text/javascript">
  window.initial_state = {}</script>
  </body>
</html>
